home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CU Amiga Super CD-ROM 17
/
CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso
/
CUCD
/
Programming
/
DiceSource
/
master
/
Examples
/
Visual
/
VMake
/
command.c
next >
Wrap
C/C++ Source or Header
|
1994-02-01
|
53KB
|
1,492 lines
#include "vmake.h"
Prototype int build_command(char *buf, int len, char *template, char *sel);
Prototype void do_command(char *string);
Prototype int save_current(int perm);
Prototype void reset_options(void);
Prototype int set_option(struct G_OBJECT *object,char **argv);
Prototype void exec_command(char *cmd, char *sel);
Prototype void set_workdir(void);
void unload_symbols(void);
void load_symbols(void);
void add_list(struct G_LIST *list, char *name, int private);
void add_listitem(struct G_LIST *list, char *name, int private, int dirty);
#define MAX_SYMBOL 31
#define LINE_LEN 78
#define MIN_LINE 10
#define SYM_PROJCFG "CFGNAME"
static int showcmd;
/***********************************************************************************
* Procedure: get_cursel
* Synopsis: name = get_cursel();
* Purpose: Return the name associated with the current selection
***********************************************************************************/
static char *get_cursel(void)
{
struct G_OBJECT *object;
#define object_list ((struct G_LIST *)object)
/* We need to determine the currently selected file */
for(object = global.objects; object != NULL; object = object->next)
{
if ((object->class == CLASS_LIST) && object_list->sel)
return(object_list->sel->buf);
#undef object_list
}
return("");
}
/*****************************************************************************
* Procedure: GetPubScrName
* Synopsis: bool = GetPubScrName(scr, buff)
* Purpose: fill the name of public a screen int a buffer, return TRUE
* if found
*****************************************************************************/
int GetPubScrName( struct Screen * scr, UBYTE * namebuff )
{
struct List * scrlist;
struct Node * node;
namebuff[0] = 0;
if (AslBase) /* need Dos 2.0 or higher for this trick */
if(scrlist = LockPubScreenList())
{
/* traverse the public screen node list looking for our screen */
for ( node = scrlist->lh_Head; node->ln_Succ; node = node->ln_Succ )
{
if ( ((struct PubScreenNode *)node)->psn_Screen == scr )
{
strcpy( namebuff, node->ln_Name );
break;
}
}
UnlockPubScreenList();
}
return( namebuff[0] ? TRUE : FALSE );
} // GetPubScrName()
/***********************************************************************************
* Procedure: build_command
* Synopsis: rc = build_command(buf, len, template)
* Purpose: Construct a command to be issued
* The template may have % strings in it where we will substitute:
* %s - Current selection
* %f - The current DMAKEFILE
* %o - An optional selection
* %t - The object module version of a file
* %r - Relative pathname of file
* %(x) - The expansion of symbol X
* %% - insert one literal % in the buffer
***********************************************************************************/
int build_command(char *buf, int len, char *template, char *sel)
{
char *name;
int nlen;
int makeobj;
/* note: MAX_FILENAME is greater than MAXPBUBSCREENNAME */
char exname[MAX_FILENAME+1];
while(*template && len)
{
if (*template != '%')
{
*buf++ = *template++;
len--;
}
else
{
int cvalid = 1; /* Assume valid substitution */
char req;
makeobj = 0;
req = toupper(template[1]);
template += 2; /* skip over %x */
name = sel;
switch(req)
{
case 'F':
{
BPTR savelock = 0;
if (global.homedir)
savelock = CurrentDir(global.homedir);
expand_filename(Sym_Lookup(SYM_SCRIPT), exname);
name = exname;
if (savelock)
CurrentDir(savelock);
break;
}
case '(':
{
char symbol[MAX_SYMBOL+1];
int i;
i = 0;
for(i = 0; *template && (*template != ')'); template++)
if (i < MAX_SYMBOL) symbol[i++] = *template;
symbol[i] = 0;
name = Sym_Lookup(symbol);
if (*template == ')') template++;
if (!*name)
{
i = atoi(symbol);
if ((i > 0) && (i <= NUM_CONFIG))
{
name = global.text[CONFIG_BASE-1+i];
if (name == NULL) name = "";
else
{
int rc;
/* We want to recurse to parse out any substitutions */
/* in the string. Note that in order to prevent runaway */
/* recursion, we temporarily kill the config string */
global.text[CONFIG_BASE-1+i] = "";
rc = build_command(buf, len, name, sel);
global.text[CONFIG_BASE-1+i] = name;
/* if something went wrong on the recursion, just get */
/* out of here. */
if (rc) return(i);
/* This is a little tricky, what we are doing is cheating*/
/* by letting it fill in the buffer with what is already */
/* there. This is harmless (the copy is onto itself) and*/
/* allows us to get the length checking done for free */
name = buf;
}
}
else
{
int max, istart;
switch (toupper(*symbol))
{
case 'T':
max = NUM_TEXT;
istart = 0;
break;
case 'C':
max = NUM_CONFIG;
istart = CONFIG_BASE;
break;
case 'S':
max = NUM_SUBRTN;
istart = SUBRTN_BASE;
break;
default:
max = 0;
break;
}
i = atoi(symbol+1);
if ((i > 0) && (i <= max))
{
name = global.text[istart+i-1];
}
}
}
}
break;
case 'T':
{
char *p;
if (!*name)
{
p = Sym_Lookup("EXEDIR");
name = Sym_Lookup("PROJECT");
}
else
{
p = Sym_Lookup("OD");
makeobj = 1;
}
/* we need to first copy over the output directory */
nlen = strlen(p);
if (nlen > len)
{
request(1, TEXT_BUFFOVFL, NULL, NULL);
return(1);
}
strcpy(buf, p);
buf += nlen;
len -= nlen;
}
break;
case 'N':
if (global.screen && GetPubScrName(global.screen, exname))
name = exname;
else
name = "Workbench";
break;
case 'R':
case 'S':
/* If nothing is selected, and they required a selection, let */
/* them know and abort the command */
if (!*sel)
{
request(1, TEXT_NOSEL, NULL, NULL);
return(1);
}
/* Expand pathname for 'S', not for 'R' */
if (req == 'R') break;
/* Else fall through to prepend the path to the name */
case 'O':
expand_filename(sel, exname);
name = exname;
break;
case '%':
/* interpret "%%" as just "%" and stuff it into the command */
/* buffer. Fall through to default processing for literals. */
template += 1;
default:
cvalid = 0; /* just copy literally, not a substitution */
}
if (cvalid) /* Means we're doing a substitution */
{
/* name is what we want to fill the current buffer with */
nlen = strlen(name);
if (nlen > len)
{
request(1, TEXT_BUFFOVFL, NULL, NULL);
return(1);
}
strcpy(buf, name);
if (makeobj)
{
/* If they requested a output file, we need to convert the */
/* file to an object file name */
if (nlen > 2 && (buf[nlen-2] == '.'))
buf[nlen-1] = 'o';
}
buf += nlen;
len -= nlen;
}
else /* Just copy over literally */
{
/* just do the '%' here, main loop checks length as well */
*buf++ = '%';
template -= 1; /* back up to char after '%' */
len--;
}
}
}
*buf++ = 0; /* Don't forget to null terminate the result */
return(0);
}
/***********************************************************************************
* Procedure: parse_keyword
* Synopsis: ptr = parse_keyword(str, buf);
* Purpose: Parse a keyword into the buffer
***********************************************************************************/
char *parse_keyword(char *str, char *buf)
{
int i;
/* Gather the string into a buffer */
i = 0;
while(*str == ' ') str++;
while((*str) && (*str != ' '))
{
buf[i++] = *str++;
if (i > MAX_SYMBOL) return(str);
}
buf[i] = 0;
while(*str == ' ') str++;
return(str);
}
/***********************************************************************************
* Procedure: exec_command
* Synopsis: exec_command(cmd, selection)
* Purpose: Execute the given command using appropriate substitutions
***********************************************************************************/
void exec_command(char *cmd, char *sel)
{
go_dir(global.workdir);
if (!build_command(global.cbuf, global.cbufsize, cmd, sel))
{
if (showcmd)
PostLog(global.cbuf);
IssueCommand(global.cbuf);
}
}
/***********************************************************************************
* Procedure: send_rexx
* Synopsis: send_rexx(cmd)
* Purpose: Send the rexx command to the given port name
***********************************************************************************/
void send_rexx(char *cmd)
{
char *res;
long ec;
char port[MAX_SYMBOL+1];
go_dir(global.workdir);
if (!build_command(global.cbuf, global.cbufsize, cmd, get_cursel()))
{
if (showcmd)
PostLog(global.cbuf);
/* Parse out the port name */
cmd = parse_keyword(global.cbuf, port);
/* Send the command off to rexx to be processed */
/* We will wait here until it is complete */
PlaceRexxCommandDirect(NULL, port, cmd, &res, &ec);
if (res != NULL)
{
PostLog(res);
free(res);
}
}
}
/***********************************************************************************
* Procedure: log_message
* Synopsis: log_message(msg, dorexx)
* Purpose: Output a message to the session log
***********************************************************************************/
void log_message(char *msg, int dorexx)
{
int gotmsg;
/* set RC in case build_command() fails and doesn't say why */
if (dorexx)
global.rexxrc = TEXT_BADPARM;
gotmsg = !build_command(global.cbuf, global.cbufsize, msg, get_cursel());
if (gotmsg)
PostLog(global.cbuf);
else
PostLog("-------------------");
if (dorexx)
{
if (gotmsg)
{
/* undo previous default -- build_command() worked */
global.rexxrc = 0;
strcpy(global.rexxrs, global.cbuf);
global.rexxrs[global.cbufsize] = 0;
}
}
}
/***********************************************************************************
* Procedure: set_workdir
* Synopsis: set_workdir();
* Purpose: Set the working directory based on the current directory and symbol
* values
***********************************************************************************/
void set_workdir(void)
{
if (test_dirty())
{
load_symbols();
}
go_dir(global.homedir);
UnLock(global.workdir);
global.workdir = xlockdir(Sym_Lookup("DIR"));
go_dir(global.workdir);
}
/***********************************************************************************
* Procedure: save_current
* Synopsis: rc = save_current();
* Purpose: Save the current file (if it has changed)
***********************************************************************************/
int save_current(int perm)
{
if (test_dirty())
{
int rc;
rc = request(0, TEXT_ASKSAVE,
Sym_Lookup(SYM_SCRIPT), global.text[TEXT_SAVE]);
if (!rc) return(1);
if (rc == 2)
{
load_symbols();
if (write_file()) return(1);
}
mark_clean();
}
return(0);
}
/***********************************************************************************
* Procedure: lookup_keyword
* Synopsis: kw = lookup_keyword(&p, keystr);
* Purpose: Lookup the keyword given and return the position of the next token
* (If the keyword was found). If the keyword wasn't found, -1 is returned
***********************************************************************************/
int lookup_keyword(char **bufp, char *keystr)
{
int i;
char *p;
char buf[MAX_SYMBOL+1];
p = parse_keyword(*bufp, buf);
/* Look for the keyword in the table they provided us */
for(i = 0; *keystr; keystr += strlen(keystr)+1, i++)
{
if (!stricmp(buf, keystr))
{
/* We got it. Return the end of the string for them */
*bufp = p;
return(i);
}
}
/* We didn't find the keyword, so let them know */
return(-1);
}
char cmdlist[] =
#define KEY_TRACE 0
"TRACE\0" /* Debug the program in the current mode */
#define KEY_EDIT 1
"EDIT\0" /* Invoke the editor on the current file */
#define KEY_EXEC 2
"EXEC\0" /* Execute the given command */
#define KEY_NEW 3
"NEW\0" /* RESET, Prompt for a new file name */
#define KEY_QUIT 4
"QUIT\0" /* Exit */
#define KEY_READ 5
"READ\0" /* Read a file */
#define KEY_SAVE 6
"SAVE\0" /* Save file */
#define KEY_FRONT 7
"FRONT\0" /* Pop Window to the front */
#define KEY_BACK 8
"BACK\0" /* Send Window to the back */
#define KEY_JUMP 9
"JUMP\0" /* Jump window to a given screen */
#define KEY_LOG 10
"LOG\0" /* Output a log message to the screen */
#define KEY_SCAN 11
"SCAN\0" /* Scan the directory for a file pattern list */
#define KEY_ADDR 12
"ADDR\0" /* Send a rexx command to a given port */
#define KEY_SET 13
"SET\0" /* Set a symbol to a given value */
#define KEY_CONFIG 14
"CONFIG\0"/* Change a config string */
#define KEY_CALL 15
"CALL\0" /* Execute a config string */
#define KEY_SELECT 16
"SELECT\0"/* Select an element in the file list */
#define KEY_ADD 17
"ADD\0" /* Add an element to the list */
#define KEY_DEL 18
"DEL\0" /* Delete the current item from the list */
#define KEY_LTOP 19
"LTOP\0" /* Select top item in list */
#define KEY_LBOT 20
"LBOT\0" /* Select bottom item in list */
#define KEY_LUP 21
"LUP\0" /* Select next item in list */
#define KEY_LDN 22
"LDN\0" /* Select previous item in list */
#define KEY_RECFG 23
"RECFG\0" /* Read in a config file */
#define KEY_REXXI 24
"REXXI\0" /* Set REXX mode to interactive */
;
/***********************************************************************************
* Procedure: scan_dir
* Synopsis: (void)scan_dir();
* Purpose: Scan the working directory for all potential files
***********************************************************************************/
void scan_dir(char *pat)
{
FILE *fp;
char buf[32];
if (!global.filelist) return;
if (!*pat) pat = global.text[CONFIG_FILES];
exec_command("LIST >RAM:TEMPFILE \"%r\" LFORMAT=\"%%s%%s\"", pat);
if ((fp = fopen("RAM:TEMPFILE", "r")) != NULL)
{
while(fgets(buf, 64, fp) != NULL)
{
int len;
len = strlen(buf) - 1; /* Get rid of the \n */
while(len && (buf[len-1] == ' ')) len--;
buf[len] = 0; /* Make sure we null terminate it */
add_listitem(global.filelist, buf, 0, 1);
}
fclose(fp);
}
}
/***********************************************************************************
* Procedure: do_command
* Synopsis: do_command(string);
* Purpose: Execute the command associated with a given string
***********************************************************************************/
void do_command(char *string)
{
char *p;
int cmdnum;
int postlog;
char *callstr;
int lclass;
/* EDIT - Invoke the editor on the current file */
/* EXEC cmd - Execute the given command */
/* NEW [ file | ?] - RESET, Prompt for a new file name */
/* QUIT - Exit */
/* READ [ file | ?] - Read a file */
/* RUN - Execute program in current mode */
/* SAVE [ file | ?] - Save file */
/* FRONT - Pop Window to the front */
/* BACK - Send Window to the back */
/* JUMP [screen] - Jump Window to a given screen */
/* LOG [string] - Output a long message to the screen */
set_workdir();
set_busy();
callstr = NULL;
postlog = 0;
while (*string)
{
int c;
cmdnum = lookup_keyword(&string, cmdlist);
/* Skip over the name to the rest of the command */
p = string;
/* Locate any trailing semi-colon so we can have multiple commands */
while(*string && (*string++ != ';'))
;
if ((c = string[-1]) == ';')
string[-1] = 0;
switch(cmdnum)
{
case KEY_TRACE: /* - Toggle the trace state */
showcmd = !showcmd;
break;
case KEY_EXEC: /* cmd - Execute a given command */
InitSession();
if (save_current(0)) break;
exec_command(p, get_cursel());
break;
case KEY_NEW: /* [ file | ?] - RESET, Prompt for a new file name */
{
char *ext;
int len, elen;
char buf[MAX_FILENAME+1];
global.rexxrc = TEXT_BADPROJ; /* unless another error occurs */
if (save_current(1)) break;
if (!get_filename(p, buf, FALSE)) break;
/* Now we need to see if the project already exists and warn them */
/* that they will be overwriting it. */
{
BPTR lock;
lock = Lock(buf, ACCESS_READ);
if (lock != NULL)
{
UnLock(lock);
if (!request(0, TEXT_ASKKILL, buf, NULL))
{
break;
}
}
}
/* no errors, no cancellations */
global.rexxrc = 0;
commit_filename(buf);
set_gadgets(0);
reset_options();
/* indicate that a new icon will be required */
global.oldproject = 0;
/* really trying to load a project, need to fix up ghosting */
global.unghost = 1;
/* If they didn't put an extension on the end of it, we want to */
/* automatically do that for them. We should also seed the default */
/* project name for them. */
p = Sym_Lookup(SYM_SCRIPT);
ext = global.text[CONFIG_EXT];
elen = strlen(ext);
len = strlen(p) - elen;
/* If the name is shorter than the extension OR it doesn't end with */
/* the extension, then we will put the extension on for them */
if ((len < 0) || stricmp(p+len, ext))
{
Sym_Set("PROJECT", p, NULL);
Sym_Set(SYM_SCRIPT, NULL, ext);
strcpy(global.filename, Sym_Lookup(SYM_SCRIPT));
}
else
{
p[len] = 0;
Sym_Set("PROJECT", p, NULL);
p[len] = *ext;
}
Sym_Set("TYPE", "Normal", NULL);
Sym_Set("CFLAGS", "-R -// -f -2.0 -d1", NULL);
unload_symbols();
set_gadgets(1);
}
break;
case KEY_QUIT: /* - Exit */
if (!save_current(1))
global.done = 1;
break;
case KEY_EDIT: /* - Invoke the editor on the current file */
global.rexxrc = TEXT_NOSEL; /* default error for interactive REXX */
if (save_current(0)) break;
{
struct stat stat_buf;
char *sel;
/* If the file is read-only, we want to see if we can check it out */
p = global.text[CONFIG_CO];
sel = get_cursel();
if (sel && (stat(sel, &stat_buf) >= 0))
{
if (!(stat_buf.st_mode & S_IWRITE))
{
int rc;
/* The file exists, but is read-only. See if they want us */
/* to check it out for them to work on */
rc = request(0, TEXT_ASKCO, sel, global.text[TEXT_CO]);
if (rc == 0) break; /* Don't do the edit */
if (rc == 2)
{
exec_command(global.text[CONFIG_CO], sel);
}
}
}
/* not aborting, can't be any errors... */
global.rexxrc = 0;
/* if EDPROJ config string is filled, we can do special */
/* handling for project file. */
if ((global.text[CONFIG_EDPROJ] == 0) ||
(stricmp(sel, Sym_Lookup(SYM_SCRIPT))))
{
exec_command(global.text[CONFIG_EDIT], sel);
break;
}
else
{
exec_command(global.text[CONFIG_EDPROJ], sel);
if (sel && (stat(sel, &stat_buf) < 0))
{
/* Don't try to read if it doesn't exist */
break;
}
}
}
/* Fall through to READ to use modified project file */
p = ""; /* READ will default to default to current project */
case KEY_READ: /* [ file | ?] - Read a file */
{
char *symcfg, *symnew;
char rbuff[200];
char buf[MAX_FILENAME+1];
struct stat stat_buf;
global.rexxrc = TEXT_BADPROJ; /* just in case... */
if (save_current(1)) break;
if (build_command(rbuff, 200, p, get_cursel())) break;
p = rbuff;
if (!get_filename(p, buf, FALSE)) break;
if (*buf && (stat(buf, &stat_buf) < 0))
{
request(1, TEXT_BADFILE, buf, NULL);
break;
}
commit_filename(buf);
set_gadgets(0);
reset_options();
if (read_file())
{
/* For some reason we couldn't read the file, */
/* just reset all the options to be a null value. */
reset_options();
commit_filename("");
}
else
{
global.rexxrc = 0; /* Everything's hunky dory now */
/* we're really trying to do it, lock all the gadgets */
global.unghost = 1;
}
global.oldproject = 1;
/* now see if we need to change the config file */
symcfg = Sym_Lookup(SYM_CONFIG);
symnew = Sym_Lookup(SYM_PROJCFG);
/* if the project doesn't specify a config file */
if (!symnew || (symnew[0] == '\0'))
/* revert to original default */
symnew = Sym_Lookup(SYM_ORIG_CFG);
/* if configuration file name has changed */
if (stricmp(symcfg, symnew))
{
Sym_Set(SYM_CONFIG, symnew, 0);
global.newscreen = 1; /* configuration redefines window */
global.parsefail = parse_config(symnew);
if (global.parsefail)
{
global.rexxrc = TEXT_BADPROJ;
break; /* error display in title bar */
}
}
unload_symbols();
/* If we're about to redisplay the window, defer */
/* repainting the gadgets until then */
if (!global.newscreen)
set_gadgets(1);
break;
}
case KEY_SAVE: /* [ file | ?] - Save file */
{
int changed;
char *ext;
int len, elen;
char svproj[MAX_FILENAME+1];
char newproj[MAX_FILENAME+1];
global.rexxrc = TEXT_BADPROJ; /* in case of unnamed perils */
/* save project name in case they change it */
strncpy(svproj, Sym_Lookup(SYM_SCRIPT), MAX_FILENAME);
svproj[MAX_FILENAME] = '\0';
if (!get_filename(p, newproj, TRUE))
break;
/* Now see if they have chosen a new name that already exists */
/* and warn them that they will be overwriting it. */
changed = stricmp(svproj, newproj);
if (changed)
{
BPTR lock;
lock = Lock(newproj, ACCESS_READ);
if (lock != NULL)
{
UnLock(lock);
if (!request(0, TEXT_ASKKILL, newproj, NULL))
{
break;
}
}
/* indicate that a new icon will be required */
global.oldproject = 0;
}
/* looks like they want to go through with this */
global.rexxrc = 0; /* didn't fail, don't lie to rexx */
/* If they didn't put an extension on the end of it, we want */
/* to automatically do that for them. */
ext = global.text[CONFIG_EXT];
len = strlen(newproj);
elen = strlen(ext);
/* If the name is shorter than the extension OR it doesn't end with */
/* the extension, then we will put the extension on for them */
if ((len < elen) || stricmp(newproj+len-elen, ext))
{
strncat(newproj, ext, MAX_FILENAME-len);
newproj[MAX_FILENAME] = 0;
}
commit_filename(newproj);
(void)test_dirty();
load_symbols();
if (!write_file())
{
/* JAT's usual negative logic -- means it worked */
if (changed)
{
/* Select the old project. */
handle_list(global.filelist, NULL, CLASS_SELECT, svproj, 0);
if (global.filelist->sel != NULL) /* we got it */
{
/* If it was in the list, delete it */
handle_list(global.filelist, NULL, CLASS_DEL, NULL, 0);
}
/* Now put the new project at the end or the list */
set_gadgets(0);
add_listitem(global.filelist, newproj, 1, 0);
set_gadgets(1);
}
/* Now the current state is saved in the new project file. */
mark_clean();
}
break;
}
case KEY_ADDR: /* port cmd - Send an arexx command to a given port */
InitSession();
if (save_current(0)) break;
send_rexx(p);
break;
case KEY_FRONT: /* - Pop Window to the front */
WindowToFront(global.window);
ScreenToFront(global.window->WScreen);
ActivateWindow(global.window);
break;
case KEY_BACK: /* - Send Window to the back */
WindowToBack(global.window);
break;
case KEY_JUMP: /* [screen] - Jump Window to a given screen */
/* This should only be done for 2.0..... */
if (AslBase)
{
char buf[MAXPUBSCREENNAME+1];
if (*p == 0)
{
if (NextPubScreen(global.window->WScreen, buf))
p = buf;
}
if (p)
global.screen = LockPubScreen(p);
else
global.screen = 0;
/* force main event loop to close & reopen the window */
global.newscreen = 1;
break;
}
request(1, TEXT_BADCMD, "--- JUMP Dos 1.3---", NULL);
break;
case KEY_RECFG:
if (save_current(0) == 0) /* didn't change their mind? */
{
char cfname[MAX_FILENAME+1];
char *cfp = p;
if (*cfp == 0)
if (get_work_filename(cfname, CONFIG_CFGFPAT))
cfp = cfname;
if (*cfp != 0) /* got a name from somewhere */
{
Sym_Set(SYM_CONFIG, cfp, 0);
global.newscreen = 1; /* configuration redefines window */
set_gadgets(0);
load_symbols();
global.parsefail = parse_config(cfp);
if (!global.parsefail)
{
unload_symbols();
Sym_Set(SYM_PROJCFG, cfp, 0);
global.dirtysym = DOSTRUE;
}
}
}
break;
case KEY_LOG: /* message - Output message to the log */
log_message("\n---------------------------", 0);
log_message(p, global.rexxmsgs);
postlog = 1;
break;
case KEY_SCAN: /* - Scan for a list of files */
set_gadgets(0);
scan_dir(p);
set_gadgets(1);
break;
case KEY_SET:
{
char buf[MAX_SYMBOL+1];
p = parse_keyword(p, buf);
if (buf[0] == 0)
{
request(1, TEXT_BADPARM, NULL, NULL);
break;
}
Sym_Set(buf, p, NULL);
if (buf[0] != '_')
global.dirtysym = DOSTRUE; /* to flag save_current() */
}
break;
case KEY_CONFIG:
{
char buf[MAX_SYMBOL+1];
p = parse_keyword(p, buf);
cmdnum = atoi(buf);
if ((cmdnum > 0) && (cmdnum <= NUM_CONFIG))
{
if (global.text[CONFIG_BASE-1+cmdnum])
free(global.text[CONFIG_BASE-1+cmdnum]);
global.text[CONFIG_BASE-1+cmdnum] = strdup(p);
}
else
request(1, TEXT_BADPARM, NULL, NULL);
}
break;
case KEY_SELECT:
/* Select the given name. */
handle_list(global.filelist, NULL, CLASS_SELECT, p, 0);
if (global.filelist->sel == NULL) /* we didn't select anything */
if (*p != '\0') /* and we weren't just trying to deselect */
request(1, TEXT_SELFAIL, p, NULL);
break;
case KEY_LTOP:
lclass = CLASS_LTOP;
goto listmove;
case KEY_LBOT:
lclass = CLASS_LBOT;
goto listmove;
case KEY_LUP:
lclass = CLASS_LUP;
goto listmove;
case KEY_LDN:
lclass = CLASS_LDN;
listmove:
handle_list(global.filelist, NULL, lclass, p, 0);
if (global.inrexx) /* don't nag but do rexx error codes */
if (global.filelist->sel == NULL) /* didn't select anything */
request(1, TEXT_SELFAIL, p, NULL);
break;
case KEY_ADD:
/* add an item to the file list, can specify name with command */
handle_list(global.filelist, NULL, CLASS_ADD, p, 0);
break;
case KEY_DEL:
/* Delete the current selection from the file list */
if (global.inrexx) /* error msg helpful in rexx, else irritating */
{
if (global.filelist->sel == NULL) /* can't delete nothing */
{
request(1, TEXT_NOSEL, NULL, NULL);
break; /* so don't call delete routine */
}
if (*p != '\0') /* DEl doesn't take parameters */
{
request(1, TEXT_BADPARM, NULL, NULL);
break; /* so don't call delete routine */
}
}
handle_list(global.filelist, NULL, CLASS_DEL, p, 0);
break;
case KEY_REXXI:
/* set REXX interactive mode on or off */
if (!stricmp(p, "on"))
{
/* Interactive, allows requesters */
global.rexxinter = 1;
Sym_Set(SYM_REXXINTER, "ON", NULL);
}
else
{
if (!stricmp(p, "off"))
{
/* set REXX mode to fail instead of displaying requesters */
global.rexxinter = 0;
Sym_Set(SYM_REXXINTER, "OFF", NULL);
}
else
{
request(1, TEXT_BADRMODE, p, NULL);
}
}
break;
case KEY_CALL:
if (callstr == NULL)
{
char buf[MAX_SYMBOL+1];
p = parse_keyword(p, buf);
cmdnum = atoi(buf);
if ((cmdnum > 0) &&
(cmdnum <= NUM_SUBRTN) &&
((p = global.text[cmdnum+SUBRTN_BASE-1]) != NULL) &&
*p)
{
string[-1] = c;
callstr = string;
string = p;
continue;
}
break;
}
default:
/* We have an invalid option, ignore the command and let them know */
/* about the problem with the option. */
request(1, TEXT_BADCMD, p, NULL);
/* We also don't want to process any more commands... */
string[-1] = c;
goto doneall;
}
string[-1] = c;
if ((*string == '\0') && (callstr != NULL))
{
string = callstr;
callstr = NULL;
}
}
doneall:
if (postlog)
{
log_message("---------------------------", 0);
if (!global.inrexx)
ActivateWindow(global.window);
}
set_idle();
}
/***********************************************************************************
* Procedure: reset_options
* Synopsis: reset_options()
* Purpose: Reset all the options to the default values
***********************************************************************************/
void reset_options(void)
{
#define object_list ((struct G_LIST *)object)
#define object_str ((struct G_STRING *)object)
#define object_cycle ((struct G_CYCLE *)object)
struct G_OBJECT *object;
char *p;
/* First make sure that all the right symbols are in the symbol table in the */
/* correct order. Since the symbol table routines guarentee that it will */
/* keep the order of the entries once they are there, we only need to touch */
/* the order once to keep it correct for the dmakefile. */
Sym_Clear();
p = "PROJECT\0"
"DIR\0"
"SRCS\0"
"HDRS\0"
"EXTRAS\0"
"PDEFAULT\0"
"EXEDIR\0"
"OD\0"
"PRECOMP\0"
"TYPE\0"
"RUN\0"
"CLIARGS\0"
"CFLAGS\0";
while(*p)
{
Sym_Set(p, NULL, "");
p += strlen(p)+1;
}
object = global.objects;
while(object != NULL)
{
switch(object->class)
{
case CLASS_STRING:
object_str->buf[0] = 0;
break;
case CLASS_CYCLE:
{
struct G_VALUE *val;
val = object_cycle->curval = object_cycle->values;
while(val != NULL)
{
if (val->string)
val->string->buf[0] = 0;
val = val->next;
}
}
break;
case CLASS_LIST:
{
struct G_ENTRY *ent;
ent = object_list->first;
object_list->first = object_list->top = NULL;
object_list->sel = NULL;
object_list->maxent = 0;
while(ent != NULL)
{
struct G_ENTRY *nextent;
nextent = (struct G_ENTRY *)ent->base.next;
free_mem(ent, sizeof(struct G_ENTRY));
ent = nextent;
}
}
break;
case CLASS_BUTTON:
break;
default:
object->state = 0;
break;
}
object = object->next;
}
#undef object_list
#undef object_str
#undef object_cycle
mark_clean();
UnLock(global.workdir);
global.workdir = 0;
}
/***********************************************************************************
* Procedure: unload_symbols
* Synopsis: unload_symbols();
* Purpose: Unload the symbols into the objects
***********************************************************************************/
void unload_symbols()
{
struct G_OBJECT *object, *savelist;
char *p;
#define object_list ((struct G_LIST *)object)
#define object_str ((struct G_STRING *)object)
#define object_check ((struct G_CHECK *)object)
#define object_cycle ((struct G_CYCLE *)object)
for(object = global.objects; object != NULL; object = object->next)
{
switch(object->class)
{
case CLASS_STRING:
strcpy(object_str->buf, Sym_Lookup(object_str->option));
break;
case CLASS_CYCLE:
{
char buf[MAX_SYMBOL+1];
struct G_VALUE *val;
for(val = object_cycle->values;
val != NULL;
val = (struct G_VALUE *)val->next)
{
char *arg;
/* Gather the current name into a buffer */
p = parse_keyword(val->option, buf);
arg = Sym_Lookup(buf);
if (val->string)
{
/* If the next character is a % sign, we have an exact */
/* match that we can just fill in. Otherwise it is */
/* the name of a string that we should lookup for the */
/* final symbol to fill it in with */
if (*p != '%')
{
/* Parse out the next token - this is the secondary */
/* Mode. This must match the value of the primary */
/* option if we are to take it */
parse_keyword(p, buf);
if (strcmp(buf, arg)) continue; /* Sorry, try the next one */
/* We have a match, look up the substitution value */
/* for the string buffer */
arg = Sym_Lookup(buf);
}
/* Copy the string into the object cycle buffer */
strcpy(val->string->buf, arg);
object_cycle->curval = val;
break;
}
else
{
/* Not a string entry. It must match exactly */
if (!strcmp(p, arg))
{
object_cycle->curval = val;
break;
}
}
}
}
break;
case CLASS_LIST:
if (!stricmp(object_list->option, "Files"))
{
savelist = object;
/* Populate it with all the strings from the list */
add_list(object_list, Sym_Lookup("SRCS"), 0);
add_list(object_list, Sym_Lookup("HDRS"), 0);
add_list(object_list, Sym_Lookup("EXTRAS"), 0);
add_list(object_list, Sym_Lookup(SYM_SCRIPT), 1);
}
else
{
add_list(object_list, Sym_Lookup(object_list->option), 0);
}
break;
}
}
mark_clean();
#undef object_check
#undef object_list
#undef object_str
#undef object_cycle
}
/***********************************************************************************
* Procedure: load_symbols
* Synopsis: load_symbols();
* Purpose: load the symbols from the current objects
***********************************************************************************/
void load_symbols()
{
struct G_OBJECT *object;
char *p, *arg;
#define object_list ((struct G_LIST *)object)
#define object_str ((struct G_STRING *)object)
#define object_check ((struct G_CHECK *)object)
#define object_cycle ((struct G_CYCLE *)object)
for(object = global.objects; object != NULL; object = object->next)
{
/* Don't even bother with this object if it hasn't changed */
if (!object->state & DIRTY_BIT) continue;
switch(object->class)
{
case CLASS_STRING:
Sym_Set(object_str->option, object_str->buf, NULL);
break;
case CLASS_CYCLE:
{
struct G_VALUE *val;
char buf[MAX_SYMBOL+1];
char sec[MAX_SYMBOL+1];
val = object_cycle->curval;
p = parse_keyword(val->option, buf);
if (val->string)
{
/* If the next token is a '%', we just use the string buffer */
/* as the result value */
if (*p == '%')
{
p = val->string->buf;
}
else
{
/* Special case of a cascade definition */
/* We need to set the primary definition to the secondary */
/* name and the secondary definition to the string */
parse_keyword(p, sec);
Sym_Set(sec, val->string->buf, NULL);
p = sec;
}
}
Sym_Set(buf, p, NULL);
/* Handle the one special case that we know about: */
/* TYPE <whatever> causes us to read in a new script */
if (!strcmp(buf, "TYPE"))
read_script();
}
break;
case CLASS_LIST:
{
int firsttime;
struct G_ENTRY *ent;
Sym_Set("EXTRAS", "", NULL);
Sym_Set("SRCS", "", NULL);
Sym_Set("HDRS", "", NULL);
/* Files */
/* - List of C and O files. Always relative to the current directory */
/* - Generates the SRCS and HDRS directories by splitting out based on extension. */
/* - Things ending in .C or .A go into SRCS */
/* - Things ending in .H go into HDRS */
/* - All others go into FILES_ext where ext is the extension of the file */
for(firsttime = 1, ent = object_list->first; ent != NULL;
ent = (struct G_ENTRY *)ent->base.next, firsttime = 0)
{
arg = "EXTRAS";
p = strrchr(ent->buf, '.');
if (p != NULL)
{
if ((!stricmp(p, ".c")) || (!stricmp(p, ".a"))) arg = "SRCS";
else if (!stricmp(p, ".h"))
{
char *t;
t = strrchr(ent->buf, '/');
if (t == NULL) t = strrchr(ent->buf, ':');
if (t == NULL) t = ent->buf;
arg = "HDRS";
if (p > t)
{
*p = 0;
if (!stricmp(t, Sym_Lookup("PROJECT")))
{
*p = '.';
Sym_Set("PDEFAULT", ent->buf, NULL);
}
*p = '.';
}
}
}
/* Make sure that we don't put the script in there more than */
/* once...... It is already present as the DMAKEFILE one */
if (!(ent->base.state & STATE_MASK))
{
if (stricmp(object_list->option, "Files"))
arg = object_list->option;
if (*Sym_Lookup(arg)) Sym_Set(arg, NULL, " ");
/* If the filename has spaces, we need to put it in quotes */
if (strchr(ent->buf, ' '))
{
Sym_Set(arg, NULL, "\'");
Sym_Set(arg, NULL, ent->buf);
Sym_Set(arg, NULL, "\'");
}
else
{
Sym_Set(arg, NULL, ent->buf);
}
}
}
}
break;
}
}
#undef object_check
#undef object_list
#undef object_str
#undef object_cycle
/* A couple of symbols MUST be a directory with the appropriate */
/* Directory separator character on the end of it */
/* DIR */
/* EXEDIR */
/* OD */
p = "DIR\0"
"EXEDIR\0"
"OD\0";
for (;*p; p += strlen(p)+1)
{
char *val;
int len;
val = Sym_Lookup(p);
len = strlen(val);
if (len && (val[len-1] != ':') && (val[len-1] != '/'))
Sym_Set(p, NULL, "/");
}
}
/***********************************************************************************
* Procedure: add_list
* Synopsis: add_list(list, name)
* Purpose: Add all the filenames in the named symbol table into the list object
***********************************************************************************/
void add_list(struct G_LIST *list,
char *name,
int private)
{
char buf[MAX_STRING+1];
int pos, c, state;
pos = 0;
state = 0;
do
{
c = *name++;
if (((state == 1) && (c == '\'')) || (pos && (c == ' ' || c == 0)))
{
buf[pos] = 0;
add_listitem(list, buf, private, 0);
state = 0;
pos = 0;
}
else
{
if (c == '\'') state = 1;
else if (state || (c != ' ')) buf[pos++] = c;
if (pos == MAX_STRING) pos = MAX_STRING-1;
}
} while(c);
}
/***********************************************************************************
* Procedure: add_listitem
* Synopsis: add_listitem(list, name, private, dirty)
* Purpose: Add the given name into the current list
***********************************************************************************/
void add_listitem(struct G_LIST *list, char *name, int private, int dirty)
{
struct G_ENTRY *ent, *prevent;
ent = get_mem(sizeof(struct G_ENTRY));
if (ent == NULL) return;
strcpy(ent->buf, name);
ent->base.state = private;
if (dirty)
list->base.state |= DIRTY_BIT;
/* Figure out where to add the name */
/* link the new name into the list */
if (list->first == NULL)
{
list->top = list->first = ent;
}
else
{
int i;
for (i = 0, prevent = list->first; prevent->base.next;
prevent = (struct G_ENTRY *)prevent->base.next, i++)
{
/* Make sure it isn't already in the list */
if (!stricmp(prevent->buf, name))
{
free_mem(ent, sizeof(struct G_ENTRY));
return;
}
}
prevent->base.next = (struct G_OBJECT *)ent;
ent->base.prev = (struct G_OBJECT *)prevent;
}
}